package com.yayohos.locationmanager.providers.permissionprovider;


import com.yayohos.locationmanager.LocationManager;
import com.yayohos.locationmanager.helper.LogUtils;
import com.yayohos.locationmanager.listener.PermissionListener;
import com.yayohos.locationmanager.providers.dialogprovider.DialogProvider;
import com.yayohos.locationmanager.view.ContextProcessor;

import ohos.aafwk.ability.Ability;
import ohos.app.Context;
import ohos.bundle.IBundleManager;

import java.lang.ref.WeakReference;
import java.util.Optional;

/**
 * PermissionProvider
 *
 * @Date 2021/5/26
 */
public abstract class PermissionProvider {
    private final String[] requiredPermissions;
    private WeakReference<ContextProcessor> weakContextProcessor;
    private WeakReference<PermissionListener> weakPermissionListener;
    private DialogProvider rationalDialogProvider;

    /**
     * This class is responsible to get required permissions, and notify {@linkplain LocationManager}.
     *
     * @param requiredPermissions     are required, setting this field empty will {@throws IllegalStateException}
     * @param rationaleDialogProvider will be used to display rationale dialog when it is necessary.
     *                               If this field is set
     *                                to null, then rationale dialog will not be displayed to user at all.
     * @throws IllegalStateException requiredPermissions can not be empty
     */
    public PermissionProvider(String[] requiredPermissions, DialogProvider rationaleDialogProvider) {
        if (requiredPermissions == null || requiredPermissions.length == 0) {
            throw new IllegalStateException("You cannot create PermissionProvider without any permission required.");
        }

        this.requiredPermissions = requiredPermissions.clone();
        this.rationalDialogProvider = rationaleDialogProvider;
    }

    /**
     * Return true if it is possible to ask permission, false otherwise
     *
     * @return boolean
     */
    public abstract boolean requestPermissions();


    /**
     * This method needs to be called when permission results are received
     *
     * @param requestCode  requestCode
     * @param permissions  permissions
     * @param grantResults grantResults
     */
    public abstract void onRequestPermissionsResult(int requestCode,
                                                    String[] permissions, int[] grantResults);

    /**
     * getRequiredPermissions
     *
     * @return requiredPermissions
     */
    public String[] getRequiredPermissions() {
        return requiredPermissions.clone();
    }

    /**
     * getDialogProvider
     *
     * @return rationalDialogProvider
     */
    public DialogProvider getDialogProvider() {
        return rationalDialogProvider;
    }

    /**
     * getPermissionListener
     *
     * @return PermissionListener
     */
    public PermissionListener getPermissionListener() {
        return weakPermissionListener.get();
    }

    /**
     * setPermissionListener
     *
     * @param permissionListener This will be set internally by {@linkplain LocationManager}
     *                           before any call is executed on PermissionProvider
     */
    public void setPermissionListener(PermissionListener permissionListener) {
        this.weakPermissionListener = new WeakReference<>(permissionListener);
    }

    /**
     * getContext
     *
     * @return Context 上下文
     */
    protected Context getContext() {
        return Optional.ofNullable(weakContextProcessor.get()).map(w -> w.getContext()).get();
       // return weakContextProcessor.get() == null ? null : weakContextProcessor.get().getContext();
    }

    /**
     * getAbility
     *
     * @return Ability
     */
    protected Ability getAbility() {
        return Optional.ofNullable(weakContextProcessor.get()).map(w -> w.getAbility()).get();
        //return weakContextProcessor.get() == null ? null : weakContextProcessor.get().getAbility();
    }

    /**
     * This will be set internally by {@linkplain LocationManager} before any call is executed on PermissionProvider
     *
     * @param contextProcessor contextProcessor
     */
    public void setContextProcessor(ContextProcessor contextProcessor) {
        this.weakContextProcessor = new WeakReference<>(contextProcessor);
    }

    /**
     * Return true if required permissions are granted, false otherwise
     *
     * @return hasPermission
     */
    public boolean hasPermission() {
        if (getContext() == null) {
            LogUtils.logE("Couldn't check whether permissions are granted or not "
                    + "because of PermissionProvider doesn't contain any context.");
            return false;
        }
        for (String permission : getRequiredPermissions()) {
            if (checkSelfPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * For test purposes
     *
     * @param permission 权限
     * @return getContext().verifySelfPermission(permission)
     */
    protected int checkSelfPermission(String permission) {
        return getContext().verifySelfPermission(permission);
    }

}
